﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Noris.Schedule.Support.Sql;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using Noris.Schedule.Support.Core;

namespace Noris.Schedule.Support.Green
{
    #region class EditStylesCls : Sada editačních stylů. Součást Repository.
    /// <summary>
    /// EditStylesCls : Sada editačních stylů. Součást Repository.
	/// Každý jeden editační styl v sobě nese sadu položek (načtených z databáze), které popisují jednotlivé hodnoty a jejich textovou reprezentaci.
	/// Jde tedy o poněkud odlišný prvek repozitory proti jednodušším prvkům (kde jedné hodnotě klíče odpovídá jeden záznam z databáze).
	/// </summary>
	public class EditStylesCls : RepositorySegmentCls<String, EditStyleInfo>
	{
		#region Základy
		/// <summary>
		/// Konstruktor. Na vstupu očekává maximální počet záznamů, které může držet v paměti.
		/// Pokud by načítal další záznamy, pak nejstarší z paměti uvolní.
		/// </summary>
		/// <param name="maxItemCnt">Nejvyšší počet záznamů. -1 = neomezeně. 0 = žádný !!!</param>
		public EditStylesCls(int maxItemCnt)
			: base(maxItemCnt)
		{ }
		/// <summary>
		/// Tato property vrátí SQL SELECT pro načtení jednoho záznamu s daty.
		/// SQL SELECT musí ve vhodném místě obsahovat token {{RecordNumber}}, na jehož místo jádro dosadí číslo hledaného záznamu nebo seznam čísel.
		/// Konkrétně, select by měl obsahovat frázi: "WHERE cislo_tridy {{RecordNumber}}", 
		/// jádro pak dosadí buď "WHERE cislo_tridy = 12345", 
		/// anebo dosadí "WHERE cislo_tridy in (1,2,3,4,5,6,7)", podle požadavku.
		/// Kdo nemá rád explicitní texty, určitě rád použije konstantu TOKEN_RECORD_NUMBER.
		/// </summary>
		protected override string SqlSelect
		{
			get
			{
				return EditStyleInfo.SqlSelect + " WHERE name " + TOKEN_RECORD_NUMBER;
			}
		}
		/// <summary>
		/// Háček volaný po načtení záznamu z databáze.
		/// Háček se volá i když je přepsaná virtuální metoda this.GetDataItem(), je volán před háčkem DataItemAddBefore() / DataItemValidateBefore()
		/// </summary>
		/// <param name="item"></param>
		protected override void DataItemRetrieveAfter(EditStyleInfo item)
		{
			base.DataItemRetrieveAfter(item);
		}
		#endregion
		#region Overrides, které mění charakter této repozitory z jednozáznamové na záznam obsahující sadu položek
		/// <summary>
		/// Metoda načte z databáze a vrátí záznam repozitory pro daný klíč.
		/// Tato metoda je jedna ze dvou, které fyzicky načítají data z SQL pomocí Db_Layer.GetList do seznamu prvků typu D.
		/// (Druhá metoda je LoadDataItemList.)
		/// Záznam neukládá do paměti, ale vrací jej.
		/// Záznam je následně ukládán do paměti metodou this.AddItem(), která je rovněž virtuální.
		/// </summary>
		/// <param name="recordKey">Klíč záznamu, který se má načíst</param>
		/// <param name="select">SQL SELECT, který je připraven pro načtení dat</param>
		/// <returns></returns>
        protected override EditStyleInfo LoadDataItem(string recordKey, string select, DataConnector connector)
		{
            if (connector == null) connector = GetRepositoryConnector();          // Konektor na data: dodaný, anebo ConnectUncommitted
			// Připravený SELECT načte více než jeden záznam, načítá data do seznamu řádků jedné položky EditStylesInfo:
            List<EditStyleRecordCls> items = Db_Layer.GetList<EditStyleRecordCls>(select, connector);
			EditStyleInfo info = new EditStyleInfo(items);
			if (info.Name != recordKey) return null;
            if (connector.IsTypeExternal)
                info.ExternalDataConnector = connector;
			return info;
		}
		/// <summary>
		/// Metoda načte z databáze a vrátí sadu záznamů repozitory pro sadu klíčů.
		/// Tato metoda je jedna ze dvou, které fyzicky načítají data z SQL pomocí Db_Layer.GetList do seznamu prvků typu D.
		/// (Druhá metoda je LoadDataItem.)
		/// Záznamy neukládá do paměti ale vrací je jako seznam.
		/// Seznam je následně ukládán do paměti metodou this.AddItems(), která je rovněž virtuální.
		/// </summary>
		/// <param name="keyList">Seznam klíčů záznamů, které se mají načíst</param>
		/// <param name="selectList">Seznam SQL SELECTů, které jsou připraveny pro načtení dat</param>
        protected override List<EditStyleInfo> LoadDataItemList(IEnumerable<string> keyList, List<string> selectList, DataConnector connector)
		{
            if (connector == null) connector = GetRepositoryConnector();          // Konektor na data: dodaný, anebo ConnectUncommitted
			// Nejprve načtu z databáze všechny položky podle filtru (máme připravené selecty):
			List<EditStyleRecordCls> dataList = null;
			if (selectList.Count == 1)
			{	// Pro jediný SELECT:
                dataList = Db_Layer.GetList<EditStyleRecordCls>(selectList[0], connector);
			}
			else
			{	// Klíčů je mnoho, načítáme pomocí více SELECTů:
				dataList = new List<EditStyleRecordCls>();
				foreach (string select in selectList)
                    dataList.AddRange(Db_Layer.GetList<EditStyleRecordCls>(select, connector));
			}

			// Následně je sgrupuji podle názvu, a z každé grupy vytvořím jeden editační styl:
			List<EditStyleInfo> result = new List<EditStyleInfo>();
			IEnumerable<IGrouping<string, EditStyleRecordCls>> esGroups = dataList.GroupBy<EditStyleRecordCls, string>(esi => esi.Name);
			foreach (IGrouping<string, EditStyleRecordCls> esGroup in esGroups)
			{
                EditStyleInfo info = new EditStyleInfo(esGroup);
                if (connector.IsTypeExternal)
                    info.ExternalDataConnector = connector;
				result.Add(info);
			}
			return result;
		}
		#endregion
        #region Podpora pro standardní editační styly
        /// <summary>
        /// Vrátí uživatelský text pro daný editační styl a jeho hodnotu.
        /// Pokud nebude hodnota nalezena, vrátí text "{neexistuje}".
        /// </summary>
        /// <param name="styleName">Název stylu. Pokud bude na vstupu null nebo empty, dojde k chybě.</param>
        /// <param name="value">Hledaná hodnota. Používá se pro nalezení položky stylu, IComparable.Compare(value).</param>
        /// <returns></returns>
        public string GetDispVal(string styleName, object value)
        {
            return this.GetDispVal(styleName, value, "{neexistuje}");
        }
        /// <summary>
        /// Vrátí uživatelský text pro daný editační styl a jeho hodnotu.
        /// Pokud nebude hodnota nalezena, vrátí defaultní hodnotu.
        /// </summary>
        /// <param name="styleName">Název stylu. Pokud bude na vstupu null nebo empty, dojde k chybě.</param>
        /// <param name="value">Hledaná hodnota. Používá se pro nalezení položky stylu, IComparable.Compare(value).</param>
        /// <param name="defaultText">Text, který bude vrácen pokud neexistuje editační styl nebo v něm není nalezena daná hodnota.</param>
        /// <returns></returns>
        public string GetDispVal(string styleName, object value, string defaultText)
        {
            if (String.IsNullOrEmpty(styleName))
                Throw.SysError(MessageInfo.Get("Není zadán název editačního stylu do metody Repository.EditStyles.GetDispVal()."));

            EditStyleInfo esInfo;
            if (!this.TryGetValue(styleName, out esInfo))
                return defaultText;

            EditStyleItem esItem = esInfo.ItemList.FirstOrDefault(i => (i.Value.CompareTo(value) == 0));
            if (esItem == null)
                return defaultText;
            return esItem.DisplayText;
        }
        #endregion
        #region Podpora pro editační styly postavené na enumu
        /// <summary>
        /// Vrátí textovou hodnotu pro hodnotu datovou - enumValue.
        /// Hodnota nesmí být null a musí být enum.
        /// Tyto editační styly se ukládají do cache EditStylesCls stejně jako standardní editační styly Green, ale nenačítají se z databáze.
        /// Existují dva druhy enum stylů: 1) mapovaný na editační styl Green, anebo 2) zcela izolovaný editační styl.
        /// </summary>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public string GetDispVal(object enumValue)
        {
            // Hodnota nesmí být null, typ musí být enum, a hodnota musí v rámci enumu existovat, jinak nehraju:
            if (enumValue == null) return "";
            Type enumType = enumValue.GetType();
            if (!enumType.IsEnum) return enumValue.ToString();
            if (!enumType.IsEnumDefined(enumValue)) return enumValue.ToString();

            // Určím jméno editačního stylu podle jména typu enumu:
            string name = "{" + enumType.GetNamespaceName() + "}";

            // Vyhledám jej v paměti anebo jej založím jako novou položku do paměti:
            EditStyleInfo editStyleEnum;
            if (!this.TryGetValueInMemory(name, out editStyleEnum))
                editStyleEnum = this.AddEditStyleEnum(name, enumType);
            if (editStyleEnum == null)
                return enumValue.ToString();

            // Linkovaný editační styl => hodnotu enumu převedeme na datový typ linkovaného enumu a vyhodnotíme v něm:
            if (editStyleEnum.HasLinkedEditStyle)
            {
                EditStyleInfo editStyleLink = editStyleEnum.LinkedEditStyle;
                if (editStyleLink == null) return enumValue.ToString();
                object linkValue = GetValueFromEnum(enumType, enumValue, editStyleLink.ValueType);
                return editStyleLink.GetDispVal(linkValue);
            }
            else
            {   // Explicitní enum editační styl:
                return editStyleEnum.GetDispVal(enumValue);
            }
        }
        /// <summary>
        /// Vytvoří a do paměti přidá nový editační styl pro enum, pod daným jménem, pro daný typ enumu.
        /// Detekuje informace z atributů enumu: na hlavičce enumu čte atribut EditStyleNameAttribute a z něj vyhodnotí název standardního editačního stylu (linkovaný editační styl).
        /// Pokud není uveden, tak vytváří explicitní editační styl na základě jednotlivých hodnot enumu a jejich popisků z atributu EditStyleDisplayValueAttribute (u každé hodnoty enumu).
        /// Vytvořený editační styl pak vrací.
        /// </summary>
        /// <param name="name">Jméno editačního stylu, který se má vygenerovat</param>
        /// <param name="enumType">Typ enumu</param>
        /// <returns></returns>
        protected EditStyleInfo AddEditStyleEnum(string name, Type enumType)
        {
            // Zjistíme, zda enum nese atribut [EditStyleName("")], který by nám poradil, jaký standardní editační styl (Helios Green) se má použít:
            List<EditStyleNameAttribute> attrs = enumType.GetCustomAttributes(typeof(EditStyleNameAttribute), false).Cast<EditStyleNameAttribute>().ToList();
            if (attrs.Count > 0)
            {   // Tento enum se hlásí k tomu, že je spřízněn s nějakým editačním stylem:
                string editStyleName = attrs[0].EditStyleName;
                if (!String.IsNullOrEmpty(editStyleName))
                {   // Vytvoříme linkovaný editační styl, vložíme do paměti a vrátíme jej:
                    EditStyleInfo editStyleEnum = new EditStyleInfo(name, editStyleName);
                    this.AddItem(name, editStyleEnum);
                    return editStyleEnum;
                }
            }

            // Tento enum není spřízněn se žádným editačním stylem: projdeme jeho položky a vytvoříme z nich generický editační styl s explicitní hodnotou:
            List<EditStyleItem> items = new List<EditStyleItem>();
            System.Reflection.FieldInfo[] fields = enumType.GetFields();
            int position = 0;
            foreach (System.Reflection.FieldInfo field in fields)
            {
                if (!field.IsStatic) continue;               // Zajímají nás pouze statické fields = jednotlivé hodnoty enumu. Instanční fields nás nezajímají.
                object value = field.GetValue(null);
                string text = null;
                EditStyleDisplayValueAttribute displayValueAttr = field.GetCustomAttributes(typeof(EditStyleDisplayValueAttribute), false).Cast<EditStyleDisplayValueAttribute>().FirstOrDefault();
                if (displayValueAttr != null)
                {
                    text = displayValueAttr.DisplayText;
                }
                else
                {
                    text = value.ToString();
                }
                EditStyleItem item = new EditStyleItem((IComparable)value, ++position, text);
                items.Add(item);
            }
            if (items.Count > 0)
            {
                EditStyleInfo editStyleExpl = new EditStyleInfo(name, items);
                this.AddItem(name, editStyleExpl);
                return editStyleExpl;
            }
            return null;
        }
        /// <summary>
        /// Konveruje hodnotu enumu na hodnotu odpovídající linkovanému editačnímu stylu.
        /// </summary>
        /// <param name="enumType"></param>
        /// <param name="enumValue"></param>
        /// <param name="valueType"></param>
        /// <returns></returns>
        protected object GetValueFromEnum(Type enumType, object enumValue, EditStyleValueType valueType)
        {
            Type underType = Enum.GetUnderlyingType(enumType);
            int intValue = 0;
            if (underType == typeof(Int32) || underType == typeof(Int16) || underType == typeof(byte) || underType == typeof(sbyte) || underType == typeof(short))
            {
                intValue = (int)enumValue;
            }
            else
            {
                intValue = (int)((long)enumValue);
            }

            object value = null;
            switch (valueType)
            {
                case EditStyleValueType.Integer:
                    value = intValue;
                    break;
                case EditStyleValueType.Text:
                    value = ((char)intValue).ToString();
                    break;
            }
            return value;
        }
        #endregion
    }
    #endregion
    #region class EditStylesInfo : Jeden editační styl. Součást (datový objekt) v EditStylesCls.
    /// <summary>
    /// EditStylesInfo : Jeden editační styl. Součást (datový objekt) v EditStylesCls.
	/// Obsahuje seznam hodnot EditStyleItem
	/// </summary>
    public class EditStyleInfo : RepositorySegmentItem<String>, IEditStyleList
	{
        #region Abstract and overrides
        /// <summary>
        /// Klíčová hodnota záznamu. Potomek musí implementovat = namapovat na konkrétní property, která nese skutečný klíč záznamu.
        /// </summary>
        protected override String CurrentKeyValue { get { return this.Name; } set { this.Name = value; } }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "Edit style: " + this.Name;
        }
        #endregion
		#region Konstrukce, prvotní naplnění daty
		/// <summary>
		/// Konstruktor
		/// </summary>
		public EditStyleInfo()
		{
			this.Items = null;
		}
        /// <summary>
        /// Konstruktor pro editační styl, který se váže na jiný editační styl.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="linkToEditStyle"></param>
        public EditStyleInfo(string name, string linkToEditStyle)
        {
            this.Items = new Dictionary<IComparable, EditStyleItem>();
            this.Name = name;
            this.ValueType = EditStyleValueType.LinkedEnumeration;
            this.LinkedEditStyleName = linkToEditStyle;
        }
        /// <summary>
        /// Konstruktor pro editační styl, který obsahuje explicitně vyjmenované položky (je typu EditStyleValueType.ExplicitEnumeration).
        /// </summary>
        /// <param name="name"></param>
        /// <param name="items"></param>
        public EditStyleInfo(string name, IEnumerable<EditStyleItem> items)
        {
            this.Items = new Dictionary<IComparable, EditStyleItem>();

            foreach (EditStyleItem item in items)
            {
                if (item.Value == null) continue;
                if (this.Items.ContainsKey(item.Value)) continue;
                this.Items.Add(item.Value, item);
            }

            this.Name = name;
            this.InputType = EditStyleInputType.DropDownListbox;
            this.ValueType = EditStyleValueType.ExplicitEnumeration;
        }
        /// <summary>
		/// Konstruktor.
        /// Zpracuje dodanou skupinu záznamů (pocházejí z dat načtených FROM lcs.editstyles) a vytvoří z nich úhledný balíček editačního stylu.
		/// </summary>
        /// <param name="records">Seznam položek s jednotlivými hodnotami editačního stylu</param>
		public EditStyleInfo(IEnumerable<EditStyleRecordCls> records)
		{
            this.Items = new Dictionary<IComparable, EditStyleItem>();

            bool saveFirst = true;
            foreach (EditStyleRecordCls record in records)
            {
                EditStyleItem item = new EditStyleItem(record);
                bool isNull = (item.Value == null);
                if (!isNull && this.Items.ContainsKey(item.Value)) continue;

                if (saveFirst)
                {
                    this.Name = record.Name;
                    this.MaskNet = record.MaskNet;
                    this.InputType = ConvertInputType(record.Type);
                    saveFirst = false;
                }

                if (!isNull)
                {
                    if (this.ValueType == EditStyleValueType.None)
                        this.ValueType = ConvertValueType(record.EnumDataValueType);
                    this.Items.Add(item.Value, item);
                }
            }
		}
        /// <summary>
        /// Položky indexované dle jejich hodnoty
        /// </summary>
        protected Dictionary<IComparable, EditStyleItem> Items;
		#endregion
		#region Public data property
		///<summary><para>Atribut: Název</para><para>Db: lcs.editstyles.name (varchar (30) not null)</para></summary>
		public string Name { get; private set; }
		///<summary><para>Db: lcs.editstyles.mask_net (varchar (40) null)</para></summary>
        public string MaskNet { get; private set; }
        /// <summary>
        /// Režim zadávání dat editačního stylu (CheckBox, RadioButton, DropDownLisbox, EditMask)
        /// </summary>
        public EditStyleInputType InputType { get; private set; }
        /// <summary>
        /// Druh hodnoty dat editačního stylu (string, int, decimal, enum)
        /// </summary>
        public EditStyleValueType ValueType { get; private set; }
        /// <summary>
        /// Příznak, že tento editační styl má položky (this.ItemList)
        /// </summary>
        public bool HasItems { get { return (this.Items != null && this.Items.Count > 0); } }
        /// <summary>
        /// Sada položek editačního stylu. Nesetříděný, rychlejší než this.ItemListSorted
        /// Nikdy není null, vždy obsahuje přinejmenším jednu položku.
        /// </summary>
        public IEnumerable<EditStyleItem> ItemList { get { return this.Items.Values; } }
        /// <summary>
        /// Sada položek editačního stylu. Je setříděn podle Position.
        /// Nikdy není null, vždy obsahuje přinejmenším jednu položku.
        /// </summary>
        public IEnumerable<EditStyleItem> ItemListSorted
        {
            get 
            {
                List<EditStyleItem> items = new List<EditStyleItem>(this.Items.Values);
                items.Sort(EditStyleItem.CompareByPosition);
                return items;
            }
        }
        /// <summary>
        /// Jméno linkovaného editačního stylu.
        /// Používá se u editačního stylu, který je založen pro určitý enum, který má definován spřízněný standardní editační styl (právě tento).
        /// </summary>
        public string LinkedEditStyleName { get; private set; }
        /// <summary>
        /// Příznak, že tento editační styl využívá linkovaný styl this.LinkedEditStyle
        /// </summary>
        public bool HasLinkedEditStyle
        {
            get
            {
                if (this.ValueType != EditStyleValueType.LinkedEnumeration) return false;
                return (!String.IsNullOrEmpty(this.LinkedEditStyleName));
            }
        }
        /// <summary>
        /// Linkovaný editační styl.
        /// Anebo null, když zde není linkovaný editační styl, anebo tento neexistuje.
        /// </summary>
        public EditStyleInfo LinkedEditStyle
        {
            get
            {
                if (!this.HasLinkedEditStyle) return null;
                EditStyleInfo editStyle = Repository.EditStyles[this.LinkedEditStyleName];
                if (editStyle == null) return null;

                if (editStyle.HasLinkedEditStyle)
                    return editStyle.LinkedEditStyle;
                else
                    return editStyle;
            }
        }
		#endregion
        #region interface IEditStyle
        /// <summary>
        /// Soupis položek, které se v rámci editačního stylu nabízejí.
        /// </summary>
        IEnumerable<IEditStyleItem> IEditStyleList.Items { get { return this.ItemListSorted; } }
        #endregion
		#region Static generátor SQL selectu
		/// <summary>
		/// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
		/// </summary>
		public static string SqlSelect { get { return EditStyleRecordCls.SqlSelect; } }
		#endregion
		#region Overrides
		/// <summary>
		/// Háček, který je zavolán po načtení dat.
		/// </summary>
		protected override void RetrieveAfter()
		{
			base.RetrieveAfter();
		}
		#endregion
		#region Konverze hodnoty na DisplayText
		/// <summary>
		/// Vrací textovou hodnotu (popisek) odpovídající datové hodnotě (value)
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public string GetDispVal(object value)
		{
			if (value == null) return "";
            IComparable key = this.GetDataValue(value);
            if (key == null) return value.ToString();
            EditStyleItem item;
            if (!this.Items.TryGetValue(key, out item)) return key.ToString();
            return item.DisplayText;
		}
        private IComparable GetDataValue(object value)
        {
            if (value is IComparable) return (IComparable)value;
            return value.ToString();
        }
		#endregion
		#region Rozšíření o další data
        /// <summary>
        /// Vrátí druh vstupního pole pro daný editační styl
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static EditStyleInputType ConvertInputType(SqlInt32 value)
        {
            if (value.IsNull) return EditStyleInputType.None;
            switch (value.Value)
            {
                case 85: return EditStyleInputType.CheckBox;
                case 86: return EditStyleInputType.RadioButton;
                case 87: return EditStyleInputType.DropDownListbox;
                case 90: return EditStyleInputType.EditMask;
            }
            return EditStyleInputType.None;
        }
        /// <summary>
        /// Vrátí typ datové hodnoty pro daný editační styl
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static EditStyleValueType ConvertValueType(SqlInt32 value)
        {
            if (value.IsNull) return EditStyleValueType.None;
            switch (value.Value)
            {
                case 1: return EditStyleValueType.Text;
                case 2: return EditStyleValueType.Integer;
                case 3: return EditStyleValueType.DecimalNumber;
                case 98: return EditStyleValueType.LinkedEnumeration;
                case 99: return EditStyleValueType.ExplicitEnumeration;
            }
            return EditStyleValueType.None;
        }
        #endregion
	}
    #endregion
    #region class EditStyleItem : Jedna položka editačního stylu, ukládaná do EditStyleInfo.
    /// <summary>
    /// EditStyleItem : Jedna položka editačního stylu, ukládaná do EditStyleInfo.
    /// </summary>
    public class EditStyleItem : IEditStyleItem
    {
        public EditStyleItem(EditStyleRecordCls record)
        {
            this.Value = record.Value;
            this.ListPosition = record.ListPosition;
            this.DisplayText = record.DispVal;
        }
        public EditStyleItem(IComparable value, int position, string text)
        {
            this.Value = value;
            this.ListPosition = position;
            this.DisplayText = text;
        }
        public override string ToString()
        {
            return this.Value + ": " + this.DisplayText;
        }
        /// <summary>
        /// Hodnota prvku (string, int, decimal, enum)
        /// </summary>
        public IComparable Value { get; private set; }
        /// <summary>
        /// Pozice prvku v nabídce
        /// </summary>
        public int ListPosition { get; private set; }
        /// <summary>
        /// Textová reprezentace hodnoty
        /// </summary>
        public string DisplayText { get; private set; }
        /// <summary>
        /// Komparátor podle ListPosition (a poté podle Value)
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static int CompareByPosition(EditStyleItem a, EditStyleItem b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;
            int cmp = a.ListPosition.CompareTo(b.ListPosition);
            if (cmp != 0) return cmp;
            return a.Value.CompareTo(b.Value);
        }
    }
    #endregion
    #region interface IEditStyleList, IEditStyleMask, IEditStyleItem : podpora pro obecně zadaný editační styl typu List
    /// <summary>
    /// IEditStyleList : deklaruje editační styl typu List z hlediska jeho používání.
    /// Předepisuje soupis položek IEditStyleItem.
    /// </summary>
    public interface IEditStyleList
    {
        /// <summary>
        /// Soupis položek, které se v rámci editačního stylu nabízejí.
        /// </summary>
        IEnumerable<IEditStyleItem> Items { get; }
    }
    /// <summary>
    /// IEditStyleItem : deklaruje jednu položku editačního stylu
    /// </summary>
    public interface IEditStyleItem
    {
        /// <summary>
        /// Hodnota prvku (string, int, decimal, enum)
        /// </summary>
        IComparable Value { get; }
        /// <summary>
        /// Textová reprezentace hodnoty
        /// </summary>
        string DisplayText { get; }
    }
    #endregion
    #region class EditStyleRecordCls : Jedna položka editačního stylu, načtená z databáze z tabulky lcs.editstyles. Slouží pouze k načtení z databáze a přípravě dat v EditStyleInfo, ale trvale se neukládá.
    /// <summary>
    /// EditStyleRecordCls : Jedna položka editačního stylu, načtená z databáze z tabulky lcs.editstyles. Slouží pouze k načtení z databáze a přípravě dat v EditStyleInfo, ale trvale se neukládá.
    /// Do instance EditStyleInfo se ukládají položky třídy EditStyleItem.
	/// </summary>
	public class EditStyleRecordCls : IDbRecord
    {
        #region Konstrukce a overrides
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.DataVal + ": " + this.DispVal;
        }
        #endregion
        #region Public data property
        ///<summary><para>Atribut: Název</para><para>Db: lcs.editstyles.name (varchar (30) not null)</para></summary>
        internal string Name { get { return _name; } }
		///<summary><para>Atribut: Typ</para><para>Db: lcs.editstyles.type (smallint not null)</para></summary>
        internal Int16 Type { get { return _type; } }
		///<summary><para>Atribut: Zobrazovaná hodnota</para><para>Db: lcs.editstyles.disp_val (varchar (255) null)</para></summary>
		public string DispVal { get { return _disp_val; } }
		///<summary><para>Atribut: Databázová hodnota</para><para>Db: lcs.editstyles.data_val (varchar (254) null)</para></summary>
		public string DataVal { get { return _data_val; } }
		///<summary><para>Atribut: Pořadí</para><para>Db: lcs.editstyles.position (int null)</para></summary>
		public SqlInt32 Position { get { return _position; } }
		///<summary><para>Atribut: Datový typ výčtu [enum_data_value_type] {1=Řetězec; 2=Celé číslo; 3=Desetinné číslo}</para><para>Db: lcs.editstyles.enum_data_value_type (int null)</para></summary>
		internal SqlInt32 EnumDataValueType { get { return _enum_data_value_type; } }
		///<summary><para>Db: lcs.editstyles.mask_net (varchar (40) null)</para></summary>
		public string MaskNet { get { return _mask_net; } }
		#endregion
		#region Protected data fields
#pragma warning disable 1591
		protected string _name;
		protected Int16 _type;
		protected string _disp_val;
		protected string _data_val;
		protected SqlInt32 _position;
		protected SqlInt32 _enum_data_value_type;
		protected string _mask_net;
#pragma warning restore 1591
		#endregion
		#region IDbRecord
		int IDbRecord.RecordNumber { get; set; }
		/// <summary>
		/// Metoda, která umožní rychle naplnit záznam daty z přicházejícího datareaderu.
		/// Typové čtení zajišťuje mapa, metodou map.GetItem...(string columnName).
		/// Metoda má vracet true = data byla skutečně načtena a do záznamu uložena (false = nedošlo k tomu, data se budou načítat genericky).
		/// </summary>
		/// <param name="reader"></param>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbFill.FillFromReader(SqlDataReader reader, FieldMapperLoad map)
		{
			_name = (string)map.FillDataIntoField<string>("name", reader);
			_type = (Int16)map.FillDataIntoField<Int16>("type", reader);
			_disp_val = (string)map.FillDataIntoField<string>("disp_val", reader);
			_data_val = (string)map.FillDataIntoField<string>("data_val", reader);
			_position = (SqlInt32)map.FillDataIntoField<SqlInt32>("position", reader);
			_enum_data_value_type = (SqlInt32)map.FillDataIntoField<SqlInt32>("enum_data_value_type", reader);
			_mask_net = (string)map.FillDataIntoField<string>("mask_net", reader);
			return true;
		}
		/// <summary>
		/// Metoda, ve které datový objekt připraví podklady pro uložení svých dat do databáze.
		/// Objekt svoje proměnné vloží do exportní mapy prostřednictvím metod map.AddTable(); map.AddColumn();
		/// Pokud objekt chce plnit více tabulek, plní je do mapy postupně, vždy v pořadí {tabulka, sloupce tabulky; další tabulka; sloupce}.
		/// Po naplnění mapy se vrací true.
		/// </summary>
		/// <param name="map"></param>
		/// <returns></returns>
		bool IDbRecord.PrepareSaveData(FieldMapperSave map)
		{ return false; }
		#endregion
        #region Static generátor SQL selectu
        /// <summary>
        /// SQL SELECT pro načtení columnů, odpovídajících této struktuře. Pozor: neobsahuje filtr ani order.
        /// </summary>
        public static string SqlSelect { get { return @"SELECT name, type, disp_val, data_val, position, enum_data_value_type, mask_net FROM lcs.editstyles"; } }
        #endregion
        #region Přidané property, používané při zpracování dat záznamu
        /// <summary>
        /// Hodnota této položky konvertovaná na odpovídající datový typ (podle this.EnumDataValueType).
        /// Pokud nelze konverotvat, je zde null.
        /// </summary>
        public IComparable Value
        {
            get
            {
                if (this.EnumDataValueType.IsNull) return null;
                switch (this.EnumDataValueType.Value)
                {
                    case 1:
                        if (this.DataVal == null) return null;
                        return this.DataVal.Trim();
                    case 2:
                        int valueInt;
                        if (Int32.TryParse(this.DataVal, out valueInt))
                            return valueInt;
                        return null;
                    case 3:
                        decimal valueDec;
                        if (Decimal.TryParse(this.DataVal, out valueDec))
                            return valueDec;
                        return null;
                }
                return null;
            }
        }
        /// <summary>
        /// Pořadí v seznamu, null je nahrazeno 0
        /// </summary>
        public int ListPosition
        {
            get
            {
                if (this.Position.IsNull) return 0;
                return this.Position.Value;
            }
        }
        #endregion
    }
    #endregion
    #region Enumy
    /// <summary>
    /// Režim zadávání dat editačního stylu
    /// </summary>
    public enum EditStyleInputType
    {
        None = 0,
        CheckBox = 85,
        RadioButton = 86,
        DropDownListbox = 87,
        EditMask = 90
    }
    /// <summary>
    /// Druh hodnoty dat editačního stylu
    /// </summary>
    public enum EditStyleValueType
    {
        /// <summary>
        /// Nic
        /// </summary>
        None = 0,
        /// <summary>
        /// Řetězec
        /// </summary>
        Text = 1,
        /// <summary>
        /// Celé číslo
        /// </summary>
        Integer = 2,
        /// <summary>
        /// Desetinné číslo
        /// </summary>
        DecimalNumber = 3,
        /// <summary>
        /// Enum linkovaný na jiný standardní editační styl (property LinkedEditStyle)
        /// </summary>
        LinkedEnumeration = 98,
        /// <summary>
        /// Enum s přímo vyčíslenými hodnotami (text uvedený u hodnoty enumu)
        /// </summary>
        ExplicitEnumeration = 99
    }
    #endregion
}
